#include <ximera/input/iinputsystem.hpp>
#include <ximera/input/idevice.hpp>
#include <ximera/input/ikeyboard.hpp>
#include <ximera/input/imouse.hpp>

namespace ximera { namespace input
{
    // IInputSystem
    IInputSystem::~IInputSystem()
    {
    }

    Signal<IInputSystem::OnConnectDeviceEvent>& IInputSystem::onConnectDevice() 
    { 
        return _onConnectDevice; 
    }

    Signal<IInputSystem::OnDisconnectDeviceEvent>& IInputSystem::onDisconnectDevice() 
    { 
        return _onDisconnectDevice; 
    }

    // IDevice
    IDevice::IDevice()
    {
        axisThresholdInt(5);
    }

    IDevice::~IDevice()
    {
    }

    Signal<IDevice::OnAxisChangeEvent>& IDevice::onAxisChange()
    {
        return _onAxisChange;
    }

    Signal<IDevice::OnAxisIntChangeEvent>& IDevice::onAxisIntChange()
    {
        return _onAxisIntChange;
    }

    Signal<IDevice::OnButtonChangeEvent>& IDevice::onButtonChange()
    {
        return _onButtonChange;
    }

    Signal<IDevice::OnButtonDownEvent>& IDevice::onButtonDown()
    {
        return _onButtonDown;
    }

    Signal<IDevice::OnButtonUpEvent>& IDevice::onButtonUp()
    {
        return _onButtonUp;
    }

    const Real AxisMult = 32767.5f;
    const Int16 AxisMultInt = static_cast<Int16>(AxisMult);

    inline Int16 axisToInt16(Real src)
    {
        return static_cast<Int16>(src * AxisMult);
    }

    inline Real axisFromInt16(Int16 src)
    {
        return static_cast<Real>(src) / AxisMult;
    }

    Real IDevice::axisDeadZone()
    {
        return _deadZone;
    }

    void IDevice::axisDeadZone(Real deadZone)
    {
        _deadZone = deadZone;
        _deadZoneInt = axisToInt16(_deadZone);
    }

    Int16 IDevice::axisDeadZoneInt()
    {
        return _deadZoneInt;
    }

    void IDevice::axisDeadZoneInt(Int16 deadZone)
    {
        _deadZoneInt = deadZone;
        _deadZone = axisFromInt16(_deadZoneInt);
    }

    Real IDevice::axisThreshold()
    {
        return _threshold;
    }

    void IDevice::axisThreshold(Real threshold)
    {
        _threshold = threshold;
        _thresholdInt = axisToInt16(_threshold);
    }

    Int16 IDevice::axisThresholdInt()
    {
        return _thresholdInt;
    }

    void IDevice::axisThresholdInt(Int16 threshold)
    {
        _thresholdInt = threshold;
        _threshold = axisFromInt16(_thresholdInt);
    }

    Byte IDevice::buttonDeadZone()
    {
        return _buttonDeadZone;
    }

    void IDevice::buttonDeadZone(Byte deadZone)
    {
        _buttonDeadZone = deadZone;
    }

    Byte IDevice::buttonThreshold()
    {
        return _buttonThreshold;
    }

    void IDevice::buttonThreshold(Byte threshold)
    {
        _buttonThreshold = threshold;
    }

    bool IDevice::isPressed(UInt16 buttonIndex)
    {
        Byte btn = button(buttonIndex);

        return ((btn > 0) && (btn >= _buttonDeadZone));
    }

    // IKeyboard
    IKeyboard::~IKeyboard()
    {
    }

    bool IKeyboard::isKeyPressed(KeyCode const& keyCode)
    {
        return isPressed(static_cast<UInt16>(keyCode.value));
    }

    Signal<IKeyboard::OnKeyDownEvent>& IKeyboard::onKeyDown()
    {
        return _onKeyDown;
    }

    Signal<IKeyboard::OnKeyUpEvent>& IKeyboard::onKeyUp()
    {
        return _onKeyUp;
    }

    // IMouse
    IMouse::~IMouse()
    {
    }

    Signal<IMouse::OnMouseDownEvent>& IMouse::onMouseDown()
    {
        return _onMouseDown;
    }

    Signal<IMouse::OnMouseUpEvent>& IMouse::onMouseUp()
    {
        return _onMouseUp;
    }
}}
